package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.remark.RemarkClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_CREATE_TIME;
import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_LIKED_TIME;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author huanghui
 * @since 2023-07-25
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {

    private final UserClient userClient;
    private final RabbitMqHelper mqHelper;
    private final RemarkClient remarkClient;

    @Override
    public void saveReply(ReplyDTO replyDTO) {
        //1.获取登录用户
        Long userId = UserContext.getUser();
        //2. 新增回答
        InteractionReply reply = BeanUtils.toBean(replyDTO, InteractionReply.class);
        reply.setUserId(userId);
        save(reply);
        // 3.累加评论数或者累加回答数
        // 3.1.判断当前回复的类型是否是回答
        boolean isAnswer = replyDTO.getAnswerId()==null;
        if (!isAnswer) {
            lambdaUpdate().setSql("reply_times = reply_times+1")
                    .eq(InteractionReply::getId,replyDTO.getAnswerId())
                    .update();
        }

        // 4.尝试累加积分
        if (replyDTO.getIsStudent()) {
            //学生才需要累加积分
            mqHelper.send(
                    MqConstants.Exchange.LEARNING_EXCHANGE,
                    MqConstants.Key.WRITE_REPLY,
                    5
            );
        }
    }

    @Override
    public PageDTO<ReplyVO> queryReplyPage(ReplyPageQuery query, boolean forAdmin) {
        // 1.问题id和回答id至少要有一个，先做参数判断
        Long questionId = query.getQuestionId();
        Long answerId = query.getAnswerId();
        if (questionId == null && answerId == null) {
            throw new BadRequestException("问题或回答id不能都为空");
        }
        //标记当前是是否是查询问题下面的回答//
        boolean isQueryAnswer= questionId!=null;
        Page<InteractionReply> page = lambdaQuery().eq(isQueryAnswer, InteractionReply::getQuestionId, questionId)
                .eq(InteractionReply::getAnswerId, isQueryAnswer ? 0L : answerId)
                .eq(!forAdmin, InteractionReply::getHidden, false)
                .page(query.toMpPage(
                        new OrderItem(DATA_FIELD_NAME_LIKED_TIME, false),
                        new OrderItem(DATA_FIELD_NAME_CREATE_TIME, true)
                ));
        List<InteractionReply> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }
        // 3.数据处理，需要查询：提问者信息、回复目标信息、当前用户是否点赞
        Set<Long> userIds = new HashSet<>();
        Set<Long> answerIds = new HashSet<>();
        Set<Long> targetReplyIds = new HashSet<>();
        // 3.1.获取提问者id 、回复的目标id、当前回答或评论id（统计点赞信息）
        for (InteractionReply record : records) {
            if (!record.getAnonymity() || forAdmin){
                //非匿名用户
                userIds.add(record.getUserId());
            }
            answerIds.add(record.getAnswerId());
            targetReplyIds.add(record.getTargetReplyId());
        }
        // 3.2.查询目标回复，如果目标回复不是匿名，则需要查询出目标回复的用户信息
        targetReplyIds.remove(0L);
        targetReplyIds.remove(null);
        if(targetReplyIds.size()>0){
            List<InteractionReply> targetReplies = listByIds(targetReplyIds);
            Set<Long> targetUserIds = targetReplies.stream()
                    .filter(Predicate.not(InteractionReply::getAnonymity).or(r -> forAdmin))
                    .map(InteractionReply::getUserId)
                    .collect(Collectors.toSet());
            userIds.addAll(targetUserIds);
        }
        //3.3.查询用户查询用户详情
        Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
        if (userIds.size()>0) {
            List<UserDTO> users = userClient.queryUserByIds(userIds);
            userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
        }
        //2.4 查询用户点赞状态
        Set<Long> bizLiked = remarkClient.isBizLiked(answerIds);
        //4.处理VO
        List<ReplyVO> listVO = new ArrayList<>(records.size());
        for (InteractionReply r : records) {
            //4.1基础属性拷贝
            ReplyVO vo = BeanUtils.copyBean(r, ReplyVO.class);
            listVO.add(vo);
            //4.2回复人信息
            if (!r.getAnonymity() ||forAdmin ){
                UserDTO userDTO = userMap.get(r.getUserId());
                if (userDTO != null) {
                    vo.setUserName(userDTO.getName());
                    vo.setUserIcon(userDTO.getIcon());
                    vo.setUserType(userDTO.getType());
                }
            }
            // 4.3.如果存在评论的目标，则需要设置目标用户信息
            if (r.getTargetReplyId()!=null){
                UserDTO targetUser = userMap.get(r.getTargetReplyId());
                if (targetUser != null) {
                    vo.setTargetUserName(targetUser.getName());
                }
            }
            //4.4.点赞状态
            vo.setLiked(bizLiked.contains(r.getId()));
        }
        return PageDTO.of(page,listVO);
    }

    @Override
    public void hiddenReply(Long id, Boolean hidden) {
        //1.查询
        InteractionReply old = getById(id);
        if (old == null) {
            return;
        }
        //2.隐藏回答
        InteractionReply reply = new InteractionReply();
        reply.setId(id);
        reply.setHidden(hidden);
        updateById(reply);
        // 3.隐藏评论，先判断是否是回答，回答才需要隐藏下属评论
        if(old.getAnswerId()!=null && old.getAnswerId()!=0){
            // 3.1.有answerId，说明自己是评论，无需处理
            return;
        }
        // 3.2.没有answerId，说明自己是回答，需要隐藏回答下的评论
        lambdaUpdate()
                .set(InteractionReply::getHidden,hidden)
                .eq(InteractionReply::getAnswerId,id)
                .update();
    }

    @Override
    public ReplyVO queryReplyById(Long id) {
        // 1.根据id查询
        InteractionReply reply = getById(id);
        // 2.数据处理，需要查询用户信息、评论目标信息、当前用户是否点赞
        // 2.1.获取用户 id
        Set<Long> userIds = new HashSet<>();
        userIds.add(reply.getUserId());
        // 2.2.查询评论目标，如果评论目标不是匿名，则需要查询出目标回复的用户id
        if (reply.getTargetReplyId()!=null  && reply.getTargetReplyId()!=0){
            InteractionReply target = getById(reply.getTargetReplyId());
            if (!target.getAnonymity()){
                userIds.add(target.getUserId());
            }
        }
        // 2.3.查询用户详细
        Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
        if (userIds.size()>0){
            List<UserDTO> users = userClient.queryUserByIds(userIds);
            userMap=users.stream().collect(Collectors.toMap(UserDTO::getId, Function.identity()));
        }
        // 2.4.查询用户的点赞状态
        Set<Long> bizLiked = remarkClient.isBizLiked(CollUtils.singletonList(id));

        // 3.处理VO
        // 3.1.拷贝基础属性
        ReplyVO vo = BeanUtils.copyBean(reply, ReplyVO.class);
        UserDTO userDTO = userMap.get(reply.getUserId());
        // 3.2.回复人信息
        if (userDTO != null) {

            vo.setUserName(userDTO.getName());
            vo.setUserType(userDTO.getType());
            vo.setUserIcon(userDTO.getIcon());
        }
        // 3.3.目标用户
        UserDTO userTarget = userMap.get(reply.getTargetUserId());
        if (userTarget != null) {
            vo.setTargetUserName(userTarget.getName());
        }
        //3.4.点赞状态
        vo.setLiked(bizLiked.contains(id));
        return vo;
    }
}
